package com.pomelo.base.core.config;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;

import com.pomelo.base.core.bean.DbTypeEnum;

/**
 * hiberante配置
 *
 * @author biankudingcha
 * @date: 2021-07-24
 * @since 0.5.0
 */
@Configuration
@PropertySource(value = "classpath:druid.properties")
public class HibernateConfiguration {

    /**
     * 日志对象
     */
    private static final Log LOGGER = LogFactory.getLog(HibernateConfiguration.class);

    /**
     * 数据库类型
     */
    @Value("${spring.datasource.druid.dbType}")
    private String dbType;

    /**
     * 数据库方言
     */
    @Value("${spring.hibernate.dialect:#{null}}")
    private String dialect;

    /**
     * 是否初始化数据库
     */
    @Value("${spring.hibernate.hbm2ddl.auto}")
    private String auto;

    /**
     * default_schema
     */
    @Value("${spring.hibernate.default_schema}")
    private String defaultSchema;

    /**
     * 配置hibernate 数据源
     *
     * @param dataSource 数据源
     * @return LocalSessionFactoryBean
     */
    @Bean(name = "SessionFactory-defaultDataSource")
    @Autowired
    public LocalSessionFactoryBean localSessionFactoryBean(DataSource dataSource) {
        try {
            LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
            sessionFactory.setDataSource(dataSource);
            // hibernate 生成bean扫描路径
            sessionFactory.setPackagesToScan("com.pomelo.**.entity*");
            // 加载hibernate映射文件
            ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resolver.getResources("classpath*:com/pomelo/**/entity/*.hbm.xml");
            List<Resource> resourceList = new ArrayList<Resource>();
            Collections.addAll(resourceList, resources);
            if (DbTypeEnum.H2.toString().equalsIgnoreCase(dbType)) {
                for (Iterator<Resource> iter = resourceList.iterator(); iter.hasNext();) {
                    Resource resource = iter.next();
                    String fileName = resource.getFilename();
                    if (fileName.endsWith(".db.hbm.xml")) {
                        iter.remove();
                    }
                }
            } else {
                for (Iterator<Resource> iter = resourceList.iterator(); iter.hasNext();) {
                    Resource resource = iter.next();
                    String fileName = resource.getFilename();
                    if (fileName.endsWith(".h2.hbm.xml")) {
                        iter.remove();
                    }
                }
            }
            sessionFactory.setMappingLocations(resourceList.toArray(new Resource[resourceList.size()]));
            Properties hibernateProperties = new Properties();

            hibernateProperties.setProperty("hibernate.dialect", getHibernateDialect());
            if (DbTypeEnum.MYSQL.toString().equalsIgnoreCase(dbType)) {
                hibernateProperties.setProperty("hibernate.show_sql", "false");
            } else {
                hibernateProperties.setProperty("hibernate.show_sql", "true");
            }
            if ("update".equals(auto)) {
                hibernateProperties.setProperty("hibernate.hbm2ddl.auto", auto);
            } else {
                hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "none");
            }
            if (DbTypeEnum.ORACLE.toString().equalsIgnoreCase(dbType)) {
                hibernateProperties.setProperty("hibernate.default_schema", defaultSchema);
            }
            sessionFactory.setHibernateProperties(hibernateProperties);
            MultiDataSourceUtil.putLocalSessionFactory("SessionFactory-defaultDataSource", sessionFactory);
            return sessionFactory;
        } catch (IOException e) {
            LOGGER.error(e);
        }
        return null;
    }

    /**
     * 获取数据库方言
     *
     * @return String
     */
    private String getHibernateDialect() {
        if (dialect != null && !"".equals(dialect)) {
            return dialect;
        } else if (DbTypeEnum.ORACLE.toString().equalsIgnoreCase(dbType)) {
            return "org.hibernate.dialect.Oracle10gDialect";
        } else if (DbTypeEnum.MYSQL.toString().equalsIgnoreCase(dbType)) {
            return "org.hibernate.dialect.MySQL5InnoDBDialect";
        } else if (DbTypeEnum.H2.toString().equalsIgnoreCase(dbType)) {
            return "org.hibernate.dialect.H2Dialect";
        } else {
            return dialect;
        }
    }

    /**
     * 事务
     *
     * @param localSessionFactory LocalSessionFactoryBean
     * @return HibernateTransactionManager
     */
    @Bean(name = "PlatformTransactionManager-defaultDataSource")
    @Autowired
    public HibernateTransactionManager hibernateTransactionManager(LocalSessionFactoryBean localSessionFactory) {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(localSessionFactory.getObject());
        MultiDataSourceUtil.putPlatformTransactionManager("PlatformTransactionManager-defaultDataSource",
            transactionManager);
        return transactionManager;
    }
}
